
#include <BAudioInput>
#include "member_BAudioInput.h"

#define member					(*(member_BAudioInput*)_ptr)
#define member_allocate()		_ptr = new member_BAudioInput
#define member_release()		delete (member_BAudioInput*)_ptr
#define audio_member(audio)		((member_BAudioInput*)audio->_ptr)

using namespace BWE;

BList<BAudioInput*>		AudioInputList;

#ifdef _WINDOWS_SYSTEM_
void CALLBACK waveInProc(HWAVEIN hWaveIn, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2     )  
{
	if(WIM_DATA != uMsg)
		return;

	for(BList<BAudioInput*>::iterator it = AudioInputList.begin(); it != AudioInputList.end(); it++)
	{
		BAudioInput* audio = it.value();
		member_BAudioInput* mem = audio_member(audio);
		if(mem->hWaveIn == hWaveIn)
		{
			LPWAVEHDR wavHdr = (LPWAVEHDR)dwParam1;
			int size = wavHdr->dwBytesRecorded;
			char* data = wavHdr->lpData;
			mem->callback(audio, data, size);
			waveInAddBuffer(hWaveIn, wavHdr, sizeof(WAVEHDR));
			return;
		}
	}
}
   
BAudioInput::BAudioInput()
{
	member_allocate();
	int num = waveInGetNumDevs();
	for(int i = 0; i < num; i++)
	{
	    WAVEINCAPS wic;
	    waveInGetDevCaps(i, &wic, sizeof(WAVEINCAPS));
		member.deviceNames.append(wic.szPname);
	}
	AudioInputList.append(this);
}

BAudioInput::~BAudioInput()
{
	AudioInputList.remove(this);
	member_release();
}

bool BAudioInput::open()
{
	// open      
	waveInOpen(&member.hWaveIn, WAVE_MAPPER, &member.wavform, (DWORD_PTR)waveInProc, 0, CALLBACK_FUNCTION); 
   
	// prepare buffer   
	for(int i = 0; i < BUFFER_NUM; i++)
	{  
		waveInPrepareHeader(member.hWaveIn, &member.wavhdr[i], sizeof(WAVEHDR));  
		waveInAddBuffer(member.hWaveIn, &member.wavhdr[i], sizeof(WAVEHDR));  
	}
	return true;
}
bool BAudioInput::close()
{
     waveInReset(member.hWaveIn);
     for (int i = 0; i < BUFFER_NUM; i++)
     {
         waveInUnprepareHeader(member.hWaveIn, &member.wavhdr[i], sizeof(WAVEHDR));  
         delete member.wavhdr[i].lpData;
     }
	waveInClose(member.hWaveIn);
	return true;
}

bool BAudioInput::start()
{
	MMRESULT result = waveInStart(member.hWaveIn);
	switch(result)
	{
	case MMSYSERR_NOERROR:
		member.log("recording..........");
		member.recording = true;
		return true;
	case MMSYSERR_INVALHANDLE:
		member.log("Specified device handle is invalid.");
		break;
	case MMSYSERR_NODRIVER:
		member.log("No device driver is present.");
		break;
	case MMSYSERR_NOMEM:
		member.log("Unabled to allocate or lock memory.");
		break;
	}
	member.recording = false;
	return false;
}
bool BAudioInput::pause()
{
	 return stop();
}
bool BAudioInput::stop()
{
	MMRESULT result = waveInStop(member.hWaveIn);
	switch(result)
	{
	case MMSYSERR_NOERROR:
		member.log("stop recording..........");
		member.recording = false;
		return true;
	case MMSYSERR_INVALHANDLE:
		member.log("Specified device handle is invalid.");
		break;
	case MMSYSERR_NODRIVER:
		member.log("No device driver is present.");
		break;
	case MMSYSERR_NOMEM:
		member.log("Unabled to allocate or lock memory.");
		break;
	}
	member.recording = false;
	return false;
}

bool BAudioInput::recording() const
{
	return member.recording;
}

int BAudioInput::deviceNumber() const
{
	return member.deviceNames.size();
}
BString BAudioInput::deviceName(int index) const
{
	return member.deviceNames(index);
}

bool BAudioInput::audioEvent(const BAudioEvent& audioEvent)
{
	return false;
}

const BString& BAudioInput::log() const
{
	return member.logText;
}
bool BAudioInput::cleanLog()
{
	return member.logText.clear();
}
#endif
